<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>中国象棋</title>
    <style>
        h1 {
            color: red;
            text-align: center;
            font-family: '楷体';
            text-shadow: 1px 1px 2px yellow;
        }
    </style>
    <script src="./socket.io.min.js"></script>
    <script src="./dayjs.min.js"></script>
    <script src="./utils.js"></script>
    <script src="./websocket.js"></script>
</head>

<body>
    <h1>中国象棋</h1>
    <div style=" margin: 0 auto;width: 1000px">
        <button id="huiqi">悔棋</button>
        <div id="tip" style="display: flex; width: 100%; justify-content: center;">
            <div class="text"></div>
            <div class="time"></div>
        </div>
        <canvas id="chinese-chess"></canvas>
    </div>
    <script>
        const canvas = document.getElementById('chinese-chess');
        const ctx = canvas.getContext('2d');
        const huiqi = document.getElementById('huiqi')
        const tipDom = document.getElementById('tip')
        //每个格子的大小
        const latticeSize = 100;
        //行数
        const row = 9;
        //列数
        const col = 8;
        //canvas的宽度
        const width = 100 + (row * latticeSize);
        //canvas的高度
        const height = 100 + (col * latticeSize);
        //生成画板
        canvas.width = width;
        canvas.height = height;
        //每方棋子个数
        const piece_count = 16;
        //单个唯一棋子名称
        const piece_names = [{
            key: [0, 8, 16, 24],
            value: 'car'
        }, {
            key: [1, 7, 17, 23],
            value: 'horse'
        }, {
            key: [2, 6, 18, 22],
            value: 'phase'
        }, {
            key: [3, 5, 19, 21],
            value: 'soldier'
        }, {
            key: [4, 20],
            value: 'general'
        }, {
            key: [9, 10],
            value: 'gun'
        }, {
            key: [9, 10, 25, 26],
            value: 'gun'
        }, {
            key: [9, 10, 25, 26],
            value: 'gun'
        }, {
            key: [11, 12, 13, 14, 15, 27, 28, 29, 30, 31],
            value: 'soldiers'
        }];
        //棋子外边距
        const piece_margin = 10;
        //棋子数据
        // const pieces = [];
        //生成棋子数据
        // for (let i = 0; i < piece_count * 2; i++) {
        //
        // }
        // 棋子坐标 数组
        let pieces = [
            {
                x: 10,
                y: 10,
                imgName: 'red_car'
            }, {
                x: 10,
                y: 110,
                imgName: 'red_horse'
            }, {
                x: 10,
                y: 210,
                imgName: 'red_phase'
            }, {
                x: 10,
                y: 310,
                imgName: 'red_soldier'
            }, {
                x: 10,
                y: 410,
                imgName: 'red_general'
            }, {
                x: 10,
                y: 510,
                imgName: 'red_soldier'
            }, {
                x: 10,
                y: 610,
                imgName: 'red_phase'
            }, {
                x: 10,
                y: 710,
                imgName: 'red_horse'
            }, {
                x: 10,
                y: 810,
                imgName: 'red_car'
            }, {
                x: 210,
                y: 110,
                imgName: 'red_gun'
            }, {
                x: 210,
                y: 710,
                imgName: 'red_gun'
            }, {
                x: 310,
                y: 10,
                imgName: 'red_soldiers'
            }, {
                x: 310,
                y: 210,
                imgName: 'red_soldiers'
            }, {
                x: 310,
                y: 410,
                imgName: 'red_soldiers'
            }, {
                x: 310,
                y: 610,
                imgName: 'red_soldiers'
            }, {
                x: 310,
                y: 810,
                imgName: 'red_soldiers'
            }, {
                x: 910,
                y: 10,
                imgName: 'black_car'
            }, {
                x: 910,
                y: 110,
                imgName: 'black_horse'
            }, {
                x: 910,
                y: 210,
                imgName: 'black_phase'
            }, {
                x: 910,
                y: 310,
                imgName: 'black_soldier'
            }, {
                x: 910,
                y: 410,
                imgName: 'black_general'
            }, {
                x: 910,
                y: 510,
                imgName: 'black_soldier'
            }, {
                x: 910,
                y: 610,
                imgName: 'black_phase'
            }, {
                x: 910,
                y: 710,
                imgName: 'black_horse'
            }, {
                x: 910,
                y: 810,
                imgName: 'black_car'
            }, {
                x: 710,
                y: 110,
                imgName: 'black_gun'
            }, {
                x: 710,
                y: 710,
                imgName: 'black_gun'
            }, {
                x: 610,
                y: 10,
                imgName: 'black_soldiers'
            }, {
                x: 610,
                y: 210,
                imgName: 'black_soldiers'
            }, {
                x: 610,
                y: 410,
                imgName: 'black_soldiers'
            }, {
                x: 610,
                y: 610,
                imgName: 'black_soldiers'
            }, {
                x: 610,
                y: 810,
                imgName: 'black_soldiers'
            }];

        // 全部点的坐标 数组
        let dot = []
        for (let v = 0; v <= 9; v++) {
            for (let r = 0; r <= 8; r++) {
                let obj = {
                    x: (10 + (100 * v)),
                    y: (10 + (100 * r))
                }
                dot.push(obj)
            }
        }



        // 联机  // 状态 ==> 初始化： 0，走棋：1，吃子：2，悔棋： 3
        let status = 0;
        let data = { "status": status, "data": [...pieces] }

        // 缓存 历史
        let cacheHistory = []
        // 选中的棋子
        let selectedPieceObj = null
        // 当前回合是那一阵营
        let round = 'black';
        // 定时器
        let timeout = null
        // 切换阵容的提示内容
        function tip() {
            if (round == 'red') {
                round = 'black'
            } else {
                round = 'red'
            }
            tipDom.children[0].innerHTML = `当前阵营为${round == 'red' ? '红色' : '黑色'}`
        }
        // 倒计时
        function time(minute) {
            let ms = minute * 60 * 1000;
            function timeText() {
                if (ms <= 0) {
                    tip()
                    ms = minute * 60 * 1000;
                }
                let s = parseInt(ms / 1000 % 60)
                let m = parseInt(ms / 1000 / 60 % 60)
                tipDom.children[1].innerHTML = `${m < 10 ? `0${m}` : m}:${s < 10 ? `0${s}` : s}`
            }
            function setTime() {
                if (ms == minute * 60 * 1000) {
                    clearTimeout(timeout)
                    timeout = null
                }
                timeout = setTimeout(() => {
                    ms -= 1000;
                    timeText()
                    setTime()
                }, 1000)
            }
            timeText()
            setTime()

        }
        // 点击canvas 对象 触发
        canvas.addEventListener('click', e => {
            // 空白点的坐标 数组
            let empty = dot.filter(v => {
                return !pieces.some(r => r.x == v.x && r.y == v.y)
            })
            const x = e.offsetX
            const y = e.offsetY;
            pieces.forEach((piece, index) => {
                // 圆心位置
                const tempx = piece.x + 40; // 50
                const tempy = piece.y + 40; // 50
                if (x > tempx - 40 && x < tempx + 40 && y > tempy - 40 && y < tempy + 40) {
                    moveChesspiece(piece, index)
                }
            })
            empty.forEach((piece, index) => {
                // 圆心位置
                const tempx = piece.x + 40; // 50
                const tempy = piece.y + 40; // 50
                if (x > tempx - 40 && x < tempx + 40 && y > tempy - 40 && y < tempy + 40) {
                    if (selectedPieceObj === null) return
                    moveChesspiece(piece)
                }
            })
            // 移动棋子的函数
            function moveChesspiece(piece, index) {
                if (piece.imgName) {
                    // 点了棋子
                    console.log('selectedPieceObj', selectedPieceObj)
                    if (selectedPieceObj === null) {
                        selectedPieceObj = {
                            ...piece,
                            index,
                        }
                        // 第一次点了棋子
                        if (piece.imgName.indexOf(round) == -1) {
                            let cmap = round == 'red' ? '红色' : '黑色'
                            // alert(`当前是${cmap}阵营`)
                            selectedPieceObj = null
                            return
                        }
                    } else {
                        // 第二次点了棋子
                        if (playChess(selectedPieceObj, piece, pieces, index)) { // 判断第二次点击的棋子(目标棋子)是否满足第一次点击的棋子(攻击棋子)的走法规则
                            // 满足则 将目标棋子的坐标 赋值给 攻击棋子 ，同时删除攻击棋子的坐标
                            pieces[selectedPieceObj.index].x = piece.x
                            pieces[selectedPieceObj.index].y = piece.y
                            pieces.splice(index, 1)
                            ctx.clearRect(0, 0, width, height)
                            data.status = 2;
                            data.data = [...pieces]
                            setMessageToServer(data)
                        } else {
                            selectedPieceObj = null
                        }
                    }
                } else {
                    // 点了空白
                    if (!estimatePiece(selectedPieceObj, piece, pieces)) return    // 判断 该棋子 走法是否正确
                    pieces[selectedPieceObj.index].x = piece.x;
                    pieces[selectedPieceObj.index].y = piece.y;
                    ctx.clearRect(0, 0, width, height)
                    data.status = 1;
                    data.data = [...pieces]
                    setMessageToServer(data)
                }
            }
        })
        // 悔棋
        huiqi.addEventListener('click', () => {
            if (cacheHistory.length <= 1) return
            pieces = cacheHistory[cacheHistory.length - 2]
            ctx.clearRect(0, 0, width, height)
            data.status = 3;
            data.data = [...pieces]
            setMessageToServer(data)
        })

        // 绘制棋盘 方法 
        function drawContainer() {
            //大矩形盒子
            ctx.beginPath();
            ctx.moveTo(0, 0);
            ctx.lineTo(1000, 0);
            ctx.lineTo(1000, 900);
            ctx.lineTo(0, 900);
            ctx.closePath();
            ctx.fillStyle = '#e8b972';
            ctx.fill();
            //加个轮廓
            ctx.fillStyle = '#000';
            ctx.fillRect(20, 20, 960, 860);
            ctx.clearRect(30, 30, 940, 840);
            ctx.fillStyle = '#e8b972';
            ctx.fillRect(30, 30, 940, 840);
            //内部线性盒子
            ctx.beginPath();
            ctx.moveTo(50, 50);
            ctx.lineTo(950, 50);
            ctx.lineTo(950, 850);
            ctx.lineTo(50, 850);
            ctx.closePath();
            ctx.stroke();
            //画线方法
            const drawLine_y = (i) => {
                ctx.beginPath();
                ctx.moveTo(50 + (100 * i), 50);
                ctx.lineTo(50 + (100 * i), 850);
                ctx.stroke();
            }
            const drawLine_x = (i) => {
                ctx.beginPath();
                ctx.moveTo(50, 50 + (100 * i));
                ctx.lineTo(950, 50 + (100 * i));
                ctx.stroke();
            }

            //循环画线
            const cycleLine = (count, is_x) => {
                for (let i = 1; i < count; i++) {
                    is_x ? drawLine_x(i) : drawLine_y(i);
                }
            }

            //开始画线
            cycleLine(9, false);
            cycleLine(8, true);

            //擦除中间
            ctx.clearRect(450, 50, 100, 800);
            ctx.fillStyle = '#e8b972';
            ctx.fillRect(450, 50, 100, 800);

            //绘制文字
            ctx.fillStyle = '#000';
            ctx.textBaseline = 'middle';
            ctx.font = "40px 楷体";
            ctx.textAlign = 'center';
            ctx.fillText('汉', 500, 200);
            ctx.fillText('界', 500, 300);
            ctx.fillText('楚', 500, 600);
            ctx.fillText('河', 500, 700);

            //绘制交叉线
            [{
                m_x: 50,
                m_y: 350,
                l_x: 250,
                l_y: 550
            }, {
                m_x: 50,
                m_y: 550,
                l_x: 250,
                l_y: 350
            }, {
                m_x: 950,
                m_y: 350,
                l_x: 750,
                l_y: 550
            }, {
                m_x: 950,
                m_y: 550,
                l_x: 750,
                l_y: 350
            }].forEach((v) => {
                ctx.beginPath();
                ctx.moveTo(v.m_x, v.m_y);
                ctx.lineTo(v.l_x, v.l_y);
                ctx.stroke();
            });
        }

        // 绘制图片(象棋)  方法
        function drawPieces(arr) {
            cacheHistory.push(JSON.parse(JSON.stringify(arr)));
            return new Promise((res, rej) => {
                arr.forEach((v) => {
                    let img = new Image();
                    img.src = `./images/${v.imgName}.png`;
                    img.onload = function () {
                        ctx.drawImage(img, v.x, v.y, 80, 80);
                    }
                });
                res()
            })
        }


        setMessageToServer(data)


        websocket.onmessage = (e) => {
            const data = JSON.parse(e.data);
            pieces = [...data.data]
            getMessageByServer(data)
        };


        function getMessageByServer(data) {
            const { data: res, status } = data
            if (status === 0) {
                round = 'black';
                drawContainer();
                drawPieces(res);
                tip()
                time(2)
            } else if (status === 1) {
                drawContainer();
                drawPieces(res).then(() => {
                    selectedPieceObj = null;
                    tip()
                    time(2)
                })
            } else if (status === 2) {
                drawContainer();
                drawPieces(res).then((res, rej) => {
                    setTimeout(() => {
                        if (!(res.some(v => v.imgName == 'red_general') && res.some(v => v.imgName == 'black_general'))) {
                            alert('恭喜你，你已经获胜了！')
                        }
                    }, 200)
                    selectedPieceObj = null
                    tip()
                    time(2)
                })
            } else if (status === 3) {
                drawContainer();
                drawPieces(res).then(() => {
                    cacheHistory.pop()
                    cacheHistory.pop()
                    selectedPieceObj = null;
                    tip()
                    time(2)
                })
            }

            // TODO  //
            //  1. 回合切换 提示;  
            //  2.运动的棋子明显(阴影，动画); 
            //  3.悔棋直接悔一个回合;  
            //  4.关闭网页棋局不变;  
            //  5. 当客户端超过三个时如何;
        }

    </script>
</body>

</html>